import hashlib
import os
import queue
import socket
import threading
import time
import tkinter as tk
from datetime import datetime
from tkinter import filedialog, messagebox, scrolledtext

import ttkbootstrap as ttkb
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


class Device:
    """设备类，用于存储连接设备的信息和状态"""

    def __init__(self, client_socket, address):
        self.socket = client_socket
        self.address = address  # (ip, port)
        self.ip = address[0]
        self.connected = True
        self.in_upgrade_mode = False
        self.upgrade_progress = 0
        self.current_version = "未知"
        self.target_version = ""
        self.last_activity = datetime.now()
        self.thread = None
        self.lock = threading.Lock()

    def update_activity(self):
        """更新最后活动时间"""
        with self.lock:
            self.last_activity = datetime.now()

    def set_version(self, version):
        """设置设备版本"""
        with self.lock:
            self.current_version = version

    def set_upgrade_mode(self, status):
        """设置升级模式状态"""
        with self.lock:
            self.in_upgrade_mode = status

    def update_progress(self, progress):
        """更新升级进度"""
        with self.lock:
            self.upgrade_progress = progress

    def close(self):
        """关闭设备连接"""
        with self.lock:
            self.connected = False
        try:
            self.socket.close()
        except:
            pass


@annotate(ClassInfo(name="DFU TCP", category="ft_tool"))
class FtTcpUpdateView(View):
    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 服务器相关变量
        self.server_socket = None
        self.server_running = False
        self.host = "0.0.0.0"  # 监听所有网络接口
        self.port = 8000
        self.clients = []  # 存储连接的设备
        self.clients_lock = threading.Lock()

        # 固件相关变量
        self.firmware_path = ""
        self.firmware_data = b""
        self.firmware_md5 = ""
        self.provided_md5 = ""
        self.packet_size = 1024  # 分包大小
        self.total_packets = 0

        # 升级状态变量
        self.upgrade_in_progress = False

        # 消息队列用于线程间通信
        self.msg_queue = queue.Queue()

        # 创建UI
        self._create_widgets()

        # 启动消息处理线程
        self.start_message_thread()

    def _create_widgets(self):
        # 创建主框架
        main_frame = ttkb.Frame(self, padding=10)
        main_frame.pack(fill=BOTH, expand=True)

        # 顶部控制区域
        control_frame = ttkb.LabelFrame(main_frame, text="服务器控制", padding=10)
        control_frame.pack(fill=X, pady=(0, 10))

        # 服务器设置区域
        server_frame = ttkb.Frame(control_frame)
        server_frame.pack(fill=X, pady=(0, 10))

        ttkb.Label(server_frame, text="服务器IP:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.host_var = tk.StringVar(value=self.host)
        ttkb.Entry(server_frame, textvariable=self.host_var, width=15).grid(
            row=0, column=1, padx=5, pady=5)

        ttkb.Label(server_frame, text="端口:").grid(row=0, column=2, padx=5, pady=5, sticky=W)
        self.port_var = tk.IntVar(value=self.port)
        ttkb.Entry(server_frame, textvariable=self.port_var, width=6).grid(
            row=0, column=3, padx=5, pady=5)

        self.start_server_btn = ttkb.Button(
            server_frame,
            text="启动服务器",
            command=self.toggle_server,
            bootstyle=SUCCESS
        )
        self.start_server_btn.grid(row=0, column=4, padx=5, pady=5)

        # 固件设置区域
        firmware_frame = ttkb.LabelFrame(control_frame, text="固件管理", padding=10)
        firmware_frame.pack(fill=X, pady=(0, 10))

        ttkb.Label(firmware_frame, text="固件文件:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.firmware_path_var = tk.StringVar(value="未选择文件")
        ttkb.Label(firmware_frame, textvariable=self.firmware_path_var).grid(
            row=0, column=1, padx=5, pady=5, sticky=W)
        ttkb.Button(firmware_frame, text="加载固件", command=self.load_firmware, bootstyle=OUTLINE).grid(
            row=0, column=2, padx=5, pady=5)

        # MD5校验区域
        md5_frame = ttkb.Frame(firmware_frame)
        md5_frame.grid(row=1, column=0, columnspan=3, sticky=W)

        ttkb.Label(md5_frame, text="固件MD5:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.firmware_md5_var = tk.StringVar(value="")
        ttkb.Label(md5_frame, textvariable=self.firmware_md5_var).grid(
            row=0, column=1, padx=5, pady=5, sticky=W)

        ttkb.Label(md5_frame, text="目标MD5:").grid(row=0, column=2, padx=5, pady=5, sticky=W)
        self.target_md5_var = tk.StringVar(value="")
        ttkb.Entry(md5_frame, textvariable=self.target_md5_var, width=32).grid(
            row=0, column=3, padx=5, pady=5, sticky=W)

        self.md5_check_btn = ttkb.Button(
            md5_frame,
            text="校验MD5",
            command=self.check_md5,
            bootstyle=OUTLINE,
            state=DISABLED
        )
        self.md5_check_btn.grid(row=0, column=4, padx=5, pady=5)

        # 设备列表和升级控制区域
        bottom_frame = ttkb.Frame(main_frame)
        bottom_frame.pack(fill=BOTH, expand=True)

        # 设备列表区域
        device_frame = ttkb.LabelFrame(bottom_frame, text="连接设备列表", padding=10)
        device_frame.pack(side=LEFT, fill=BOTH, expand=True, padx=(0, 10))

        # 设备列表Treeview
        columns = ("ip", "version", "status", "progress")
        self.device_tree = ttkb.Treeview(
            device_frame,
            columns=columns,
            show="headings",
            selectmode="extended"  # 支持多选
        )

        # 设置列标题和宽度
        self.device_tree.heading("ip", text="设备IP")
        self.device_tree.heading("version", text="当前版本")
        self.device_tree.heading("status", text="状态")
        self.device_tree.heading("progress", text="升级进度")

        self.device_tree.column("ip", width=120)
        self.device_tree.column("version", width=100)
        self.device_tree.column("status", width=120)
        self.device_tree.column("progress", width=100)

        # 添加滚动条
        scrollbar = ttkb.Scrollbar(device_frame, orient="vertical", command=self.device_tree.yview)
        self.device_tree.configure(yscrollcommand=scrollbar.set)

        scrollbar.pack(side=RIGHT, fill=Y)
        self.device_tree.pack(fill=BOTH, expand=True)

        # 升级控制和日志区域
        right_frame = ttkb.Frame(bottom_frame)
        right_frame.pack(side=RIGHT, fill=BOTH, expand=True)

        # 升级控制区域
        upgrade_control_frame = ttkb.LabelFrame(right_frame, text="升级控制", padding=10)
        upgrade_control_frame.pack(fill=X, pady=(0, 10))

        self.upgrade_btn = ttkb.Button(
            upgrade_control_frame,
            text="开始升级选中设备",
            command=self.start_upgrade_selected,
            bootstyle=PRIMARY,
            state=DISABLED
        )
        self.upgrade_btn.pack(fill=X, pady=5)

        self.cancel_btn = ttkb.Button(
            upgrade_control_frame,
            text="取消所有升级",
            command=self.cancel_all_upgrades,
            bootstyle=DANGER,
            state=DISABLED
        )
        self.cancel_btn.pack(fill=X, pady=5)

        # 进度条
        self.progress_var = tk.DoubleVar(value=0)
        self.progress_bar = ttkb.Progressbar(
            upgrade_control_frame,
            variable=self.progress_var,
            length=300,
            mode="determinate"
        )
        self.progress_bar.pack(fill=X, pady=5)

        # 日志区域
        log_frame = ttkb.LabelFrame(right_frame, text="升级日志", padding=10)
        log_frame.pack(fill=BOTH, expand=True)

        self.log_text = scrolledtext.ScrolledText(
            log_frame,
            wrap=tk.WORD,
            font=("Consolas", 10),
            state=tk.DISABLED
        )
        self.log_text.pack(fill=BOTH, expand=True)

        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        self.status_bar = ttkb.Label(self, textvariable=self.status_var, anchor=W)
        self.status_bar.pack(side=BOTTOM, fill=X)

    def start_message_thread(self):
        """启动消息处理线程"""
        self.running = True
        threading.Thread(target=self.process_messages, daemon=True).start()

    def process_messages(self):
        """处理消息队列中的消息"""
        while self.running:
            try:
                msg = self.msg_queue.get(timeout=0.1)
                self.log(msg)
                self.msg_queue.task_done()
            except queue.Empty:
                continue

    def log(self, message):
        """在日志区域添加消息"""
        self.log_text.config(state=tk.NORMAL)
        timestamp = time.strftime("%H:%M:%S")
        self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)
        self.status_var.set(message)

    def toggle_server(self):
        """切换服务器状态（启动/停止）"""
        if self.server_running:
            self.stop_server()
        else:
            self.start_server()

    def start_server(self):
        """启动TCP服务器"""
        try:
            self.host = self.host_var.get()
            self.port = self.port_var.get()

            # 创建TCP socket
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((self.host, self.port))
            self.server_socket.listen(5)  # 最大连接数

            self.server_running = True
            self.start_server_btn.config(text="停止服务器", bootstyle=DANGER)
            self.host_var.set(self.host)
            self.port_var.set(self.port)
            self.host_var.set(self.host)

            # 禁用服务器设置编辑
            self.host_var.set(self.host)
            self.port_var.set(self.port)

            self.log(f"服务器已启动，监听 {self.host}:{self.port}")

            # 启动服务器监听线程
            threading.Thread(target=self.accept_connections, daemon=True).start()

            # 启动客户端监控线程
            threading.Thread(target=self.monitor_clients, daemon=True).start()

        except Exception as e:
            self.log(f"启动服务器失败: {str(e)}")
            messagebox.showerror("错误", f"启动服务器失败: {str(e)}")

    def stop_server(self):
        """停止TCP服务器"""
        try:
            self.server_running = False

            # 关闭所有客户端连接
            with self.clients_lock:
                for client in self.clients:
                    client.close()
                self.clients = []

            # 关闭服务器socket
            if self.server_socket:
                self.server_socket.close()

            self.start_server_btn.config(text="启动服务器", bootstyle=SUCCESS)
            self.log("服务器已停止")

            # 更新设备列表
            self.update_device_list()

        except Exception as e:
            self.log(f"停止服务器失败: {str(e)}")

    def accept_connections(self):
        """接受客户端连接的线程函数 - 修复版"""
        while self.server_running:
            try:
                self.server_socket.settimeout(1.0)  # 设置超时，便于退出循环
                client_socket, address = self.server_socket.accept()
                client_socket.settimeout(5.0)

                # 在单独线程中处理新连接，避免阻塞服务器
                threading.Thread(
                    target=self.handle_new_connection,
                    args=(client_socket, address),
                    daemon=True
                ).start()

            except socket.timeout:
                continue  # 超时，继续循环
            except Exception as e:
                if self.server_running:
                    self.log(f"接受连接错误: {str(e)}")
                break

    def handle_new_connection(self, client_socket, address):
        """处理新连接的线程函数 - 新增"""
        try:
            self.log(f"新设备连接: {address[0]}:{address[1]}")

            # 创建设备对象
            device = Device(client_socket, address)

            # 线程安全地添加到客户端列表
            with self.clients_lock:
                self.clients.append(device)

            # 立即更新设备列表（通过主线程）
            self.update_device_list()

            # 先进行版本查询
            self.send_command(device, "GET_VERSION")

            # 启动客户端处理线程
            device.thread = threading.Thread(
                target=self.handle_client,
                args=(device,),
                daemon=True
            )
            device.thread.start()

        except Exception as e:
            self.log(f"处理新连接时出错: {str(e)}")
            try:
                client_socket.close()
            except:
                pass

    def handle_client(self, device):
        """处理客户端通信的线程函数 - 优化版"""
        try:
            while device.connected and self.server_running:
                try:
                    # 接收数据时设置较短超时，避免阻塞
                    device.socket.settimeout(1.0)
                    data = device.socket.recv(1024)

                    if not data:
                        break  # 连接关闭

                    device.update_activity()
                    self.process_client_data(device, data)

                except socket.timeout:
                    # 超时检查是否需要继续运行
                    continue
                except Exception as e:
                    self.log(f"与 {device.ip} 通信错误: {str(e)}")
                    break

        except Exception as e:
            self.log(f"处理 {device.ip} 时出错: {str(e)}")
        finally:
            # 关闭连接
            device.close()
            self.log(f"设备 {device.ip} 已断开连接")

            # 线程安全地移除客户端
            with self.clients_lock:
                if device in self.clients:
                    self.clients.remove(device)

            # 更新设备列表
            self.update_device_list()

    def process_client_data(self, device, data):
        """处理客户端发送的数据"""
        try:
            message = data.decode('utf-8').strip()
            self.log(f"收到 {device.ip} 的消息: {message}")

            # 解析消息
            if message.startswith("VERSION:"):
                # 版本信息
                version = message.split(":", 1)[1]
                device.set_version(version)
                self.log(f"{device.ip} 版本信息: {version}")
                self.update_device_list()

            elif message == "UPGRADE_MODE_READY":
                # 设备已进入升级模式
                device.set_upgrade_mode(True)
                self.log(f"{device.ip} 已进入升级模式")
                self.update_device_list()

            elif message.startswith("PACKET_ACK:"):
                # 数据包确认
                packet_num = int(message.split(":", 1)[1])
                self.log(f"{device.ip} 已确认收到包 {packet_num}")

            elif message == "UPGRADE_COMPLETE":
                # 升级完成
                self.log(f"{device.ip} 升级完成，正在重启...")
                device.update_progress(100)
                self.update_device_list()

            elif message == "HEARTBEAT_ACK":
                # 心跳响应，无需特殊处理
                pass

            else:
                self.log(f"{device.ip} 发送了未知消息: {message}")

        except Exception as e:
            self.log(f"处理 {device.ip} 数据时出错: {str(e)}")

    def send_command(self, device, command):
        """向设备发送命令"""
        if not device.connected or not self.server_running:
            return False

        try:
            with device.lock:
                if device.connected:
                    device.socket.sendall((command + "\r\n").encode('utf-8'))
                    device.update_activity()
                    return True
            return False
        except Exception as e:
            self.log(f"向 {device.ip} 发送命令失败: {str(e)}")
            return False

    def send_data(self, device, data):
        """向设备发送二进制数据"""
        if not device.connected or not self.server_running:
            return False

        try:
            with device.lock:
                if device.connected:
                    device.socket.sendall(data)
                    device.update_activity()
                    return True
            return False
        except Exception as e:
            self.log(f"向 {device.ip} 发送数据失败: {str(e)}")
            return False

    def monitor_clients(self):
        """监控客户端连接状态的线程函数"""
        while self.server_running:
            try:
                # 检查超时客户端（5分钟无活动）
                now = datetime.now()
                with self.clients_lock:
                    for client in self.clients[:]:  # 迭代副本
                        if (now - client.last_activity).total_seconds() > 300:  # 5分钟
                            self.log(f"设备 {client.ip} 超时，断开连接")
                            client.close()
                            self.clients.remove(client)

                # 更新设备列表
                self.update_device_list()

                time.sleep(10)  # 每10秒检查一次

            except Exception as e:
                self.log(f"监控客户端时出错: {str(e)}")
                time.sleep(10)

    def update_device_list(self):
        """线程安全的设备列表更新 - 修复版"""
        # 使用after()确保在主线程中更新UI
        self.after(0, self._update_device_list_ui)

    def _update_device_list_ui(self):
        """在UI线程中更新设备列表 - 优化版"""
        # 保存当前选中项
        selected_ips = [self.device_tree.item(item, "values")[0]
                        for item in self.device_tree.selection()]

        # 清空现有项
        for item in self.device_tree.get_children():
            self.device_tree.delete(item)

        # 线程安全地获取客户端列表
        with self.clients_lock:
            # 创建客户端副本用于迭代
            clients_copy = list(self.clients)

        # 添加所有客户端
        for client in clients_copy:
            with client.lock:  # 确保线程安全访问设备数据
                if not client.connected:
                    continue

                # 确定状态文本
                if client.in_upgrade_mode:
                    status = "升级模式"
                elif client.upgrade_progress > 0 and client.upgrade_progress < 100:
                    status = "升级中"
                elif client.upgrade_progress == 100:
                    status = "升级完成"
                else:
                    status = "已连接"

                # 进度文本
                progress = f"{client.upgrade_progress}%" if client.upgrade_progress > 0 else "-"

                # 添加到列表
                item = self.device_tree.insert("", tk.END, values=(
                    client.ip,
                    client.current_version,
                    status,
                    progress
                ))

                # 恢复选中状态
                if client.ip in selected_ips:
                    self.device_tree.selection_add(item)

        # 更新升级按钮状态
        has_connected_devices = len(clients_copy) > 0
        self.upgrade_btn.config(
            state=NORMAL if has_connected_devices and self.firmware_path and self.server_running else DISABLED
        )

    def load_firmware(self):
        """加载固件文件"""
        file_path = filedialog.askopenfilename(
            title="选择固件文件",
            filetypes=[("固件文件", "*.bin;*.hex;*.firmware"), ("所有文件", "*.*")]
        )

        if file_path:
            try:
                with open(file_path, "rb") as f:
                    self.firmware_data = f.read()

                self.firmware_path = file_path
                self.firmware_path_var.set(os.path.basename(file_path))

                # 计算固件MD5
                md5_hash = hashlib.md5()
                md5_hash.update(self.firmware_data)
                self.firmware_md5 = md5_hash.hexdigest()
                self.firmware_md5_var.set(self.firmware_md5)

                # 计算总分包数
                self.total_packets = (len(self.firmware_data) + self.packet_size - 1) // self.packet_size

                self.log(
                    f"已加载固件: {os.path.basename(file_path)}, 大小: {len(self.firmware_data)} 字节, 分包数: {self.total_packets}")

                # 启用MD5校验按钮
                self.md5_check_btn.config(state=NORMAL)

                # 更新升级按钮状态
                self.update_device_list()

            except Exception as e:
                self.log(f"加载固件失败: {str(e)}")
                messagebox.showerror("错误", f"加载固件失败: {str(e)}")

    def check_md5(self):
        """校验固件MD5"""
        self.provided_md5 = self.target_md5_var.get().strip().lower()

        if not self.firmware_path:
            messagebox.showwarning("警告", "请先加载固件")
            return

        if not self.provided_md5:
            messagebox.showwarning("警告", "请输入目标MD5")
            return

        if self.firmware_md5 == self.provided_md5:
            self.log("MD5校验成功，固件匹配")
            messagebox.showinfo("成功", "MD5校验成功，固件匹配")
            return True
        else:
            self.log(f"MD5校验失败，固件MD5: {self.firmware_md5}, 目标MD5: {self.provided_md5}")
            messagebox.showerror("失败", "MD5校验失败，固件不匹配")
            return False

    def start_upgrade_selected(self):
        """开始升级选中的设备"""
        # 检查固件是否已加载
        if not self.firmware_path:
            messagebox.showwarning("警告", "请先加载固件")
            return

        # 检查MD5（如果已提供）
        self.provided_md5 = self.target_md5_var.get().strip().lower()
        if self.provided_md5 and not self.check_md5():
            return

        # 获取选中的设备
        selected_items = self.device_tree.selection()
        if not selected_items:
            messagebox.showwarning("警告", "请先选择要升级的设备")
            return

        # 获取选中设备的IP
        selected_ips = [self.device_tree.item(item, "values")[0] for item in selected_items]

        # 查找对应的设备对象
        selected_devices = []
        with self.clients_lock:
            for client in self.clients:
                if client.ip in selected_ips:
                    selected_devices.append(client)

        if not selected_devices:
            messagebox.showwarning("警告", "未找到选中的设备")
            return

        # 确认开始升级
        if not messagebox.askyesno("确认", f"确定要升级选中的 {len(selected_devices)} 台设备吗？"):
            return

        # 更新状态
        self.upgrade_in_progress = True
        self.upgrade_btn.config(state=DISABLED)
        self.cancel_btn.config(state=NORMAL)
        self.progress_var.set(0)

        self.log(f"开始升级 {len(selected_devices)} 台设备...")

        # 为每台设备启动升级线程
        for device in selected_devices:
            threading.Thread(target=self.upgrade_device, args=(device,), daemon=True).start()

    def upgrade_device(self, device):
        """升级单个设备的线程函数"""
        try:
            self.log(f"开始升级设备 {device.ip}")

            # 1. 发送命令进入升级模式
            device.update_progress(0)
            self.update_device_list()

            self.log(f"发送命令，请求 {device.ip} 进入升级模式...")
            if not self.send_command(device, "ENTER_UPGRADE_MODE"):
                raise Exception("发送进入升级模式命令失败")

            # 等待设备进入升级模式（最多等待10秒）
            success = False
            for _ in range(20):
                time.sleep(0.5)
                with device.lock:
                    if device.in_upgrade_mode:
                        success = True
                        break
                if not device.connected:
                    raise Exception("设备已断开连接")

            if not success:
                raise Exception("设备未进入升级模式")

            # 2. 发送固件信息
            firmware_size = len(self.firmware_data)
            self.log(f"向 {device.ip} 发送固件信息，大小: {firmware_size} 字节")
            if not self.send_command(device, f"FIRMWARE_INFO {firmware_size} {self.total_packets} {self.packet_size}"):
                raise Exception("发送固件信息失败")

            time.sleep(1)

            # 3. 分包发送固件
            self.log(f"开始向 {device.ip} 发送固件数据...")

            for i in range(self.total_packets):
                if not self.upgrade_in_progress or not device.connected:  # 检查是否取消升级或设备已断开
                    raise Exception("升级已取消或设备断开连接")

                # 计算当前包的起始和结束位置
                start = i * self.packet_size
                end = start + self.packet_size
                packet_data = self.firmware_data[start:end]

                # 发送包编号和大小
                if not self.send_command(device, f"PACKET {i} {len(packet_data)}"):
                    raise Exception(f"发送包 {i} 信息失败")

                time.sleep(0.05)

                # 发送包数据（二进制）
                if not self.send_data(device, packet_data):
                    raise Exception(f"发送包 {i} 数据失败")

                # 更新进度
                progress = int((i + 1) / self.total_packets * 100)
                device.update_progress(progress)
                self.update_device_list()

                # 等待确认（最多5秒）
                ack_received = False
                for _ in range(10):
                    time.sleep(0.5)
                    # 这里简化处理，实际应等待设备返回PACKET_ACK
                    ack_received = True
                    break

                if not ack_received:
                    raise Exception(f"未收到包 {i} 的确认")

            # 4. 发送升级完成命令
            if not self.send_command(device, "UPGRADE_FINISH"):
                raise Exception("发送升级完成命令失败")

            self.log(f"{device.ip} 固件发送完成，等待设备升级...")

            # 5. 等待设备升级完成并重启（最多等待30秒）
            success = False
            for _ in range(60):
                time.sleep(0.5)
                if not device.connected:
                    # 设备可能正在重启，暂时断开连接
                    time.sleep(5)  # 等待重启
                    success = True
                    break

            if not success:
                raise Exception("设备升级超时")

            # 6. 重新检查设备版本
            # 这里假设设备重启后会重新连接，实际应用中可能需要额外处理
            self.log(f"{device.ip} 升级成功，等待重新连接...")

            device.update_progress(100)
            self.update_device_list()

        except Exception as e:
            self.log(f"{device.ip} 升级失败: {str(e)}")
            with device.lock:
                device.update_progress(-1)  # 标记升级失败
            self.update_device_list()
        finally:
            # 检查是否所有设备都已完成升级
            self.check_all_upgrades_complete()

    def check_all_upgrades_complete(self):
        """检查是否所有设备都已完成升级"""
        with self.clients_lock:
            all_complete = True
            for client in self.clients:
                with client.lock:
                    if 0 < client.upgrade_progress < 100:
                        all_complete = False
                        break

            if all_complete:
                self.upgrade_in_progress = False
                self.after(0, lambda: self.cancel_btn.config(state=DISABLED))
                self.after(0, lambda: self.upgrade_btn.config(
                    state=NORMAL if len(self.clients) > 0 and self.firmware_path else DISABLED
                ))
                self.after(0, lambda: self.progress_var.set(100))
                self.log("所有升级任务已完成")

    def cancel_all_upgrades(self):
        """取消所有正在进行的升级"""
        if not messagebox.askyesno("确认", "确定要取消所有升级吗？这可能导致设备无法正常工作！"):
            return

        self.upgrade_in_progress = False
        self.log("正在取消所有升级任务...")

        # 更新设备状态
        with self.clients_lock:
            for client in self.clients:
                with client.lock:
                    if 0 < client.upgrade_progress < 100:
                        client.update_progress(0)
                        client.set_upgrade_mode(False)

        self.update_device_list()
        self.cancel_btn.config(state=DISABLED)
        self.upgrade_btn.config(
            state=NORMAL if len(self.clients) > 0 and self.firmware_path else DISABLED
        )

    def on_close(self):
        """窗口关闭时的处理"""
        self.running = False
        self.server_running = False

        # 关闭所有客户端连接
        with self.clients_lock:
            for client in self.clients:
                client.close()

        # 关闭服务器socket
        if self.server_socket:
            try:
                self.server_socket.close()
            except:
                pass

        self.destroy()

    def create_widgets(self):
        pass
